﻿// <copyright file="ColumnChartItemDataView.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008-2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-03-10</date>
// <summary>OpenWPFChart library. ColumnChartItem DataView.</summary>
// <revision>$Id$</revision>

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Windows.Media;

namespace OpenWPFChart.Parts
{
	/// <summary>
	/// ColumnChartItem DataView.
	/// </summary>
	/// <remarks>
	/// This class adds columns-related properties to its SampledCurveDataView base class.
	/// </remarks>
	public class ColumnChartItemDataView : SampledCurveDataView
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ColumnChartItemDataView"/> class.
		/// </summary>
		/// <remarks>
		/// This object VisualCue defines what curve (if any) is displayed with the Columns 
		/// (e.g. poliline, Bezier, etc.)
		/// Default VisualCue is the collection of <see cref="Type"/> objects containing two items:
		/// <see cref="ColumnVisual"/> type and <see cref="PolylineVisual"/> type.
		/// </remarks>
		public ColumnChartItemDataView()
		{
			curveVisualType = typeof(PolylineVisual);
			VisualCue = new ObservableCollection<Type>() { typeof(ColumnVisual), curveVisualType };
		}

		// Store Curve Visual type for use in IsCurveVisible property setter.
		Type curveVisualType;

		/// <summary>
		/// Extract new Curve Visual Type and store it internally.
		/// Called when VisualCue property changed.
		/// </summary>
		protected override void OnVisualCueChanged() 
		{
			base.OnVisualCueChanged();

			IList list = VisualCue as IList;
			if (list == null || list.Count < 2)
				return;
			Type type = list[1] as Type;
			if (type != null || type.IsDefined(typeof(InterpolatedAttribute), false))
				curveVisualType = type;
		}

		#region IsCurveVisible
		bool isCurveVisible = true;
		/// <summary>
		/// Gets or sets the <see cref="IsCurveVisible"/> property.
		/// </summary>
		/// <remarks>
		/// Defines if the curve is displayed along with the Columns.
		/// </remarks>
		/// <value/>
		public bool IsCurveVisible
		{
			get { return isCurveVisible; }
			set
			{
				if (isCurveVisible != value)
				{
					isCurveVisible = value;
					NotifyPropertyChanged("IsCurveVisible");
					
					if (isCurveVisible)
						VisualCue = new ObservableCollection<Type>() { typeof(ColumnVisual), curveVisualType };
					else
						VisualCue = typeof(ColumnVisual);
				}
			}
		}
		#endregion IsCurveVisible

		#region ColumnWidth
		double columnWidth = 10;
		/// <summary>
		/// Gets or sets the ColumnWidth property.
		/// </summary>
		/// <remarks>
		/// ColumnWidth in pixels; must be > 0.
		/// </remarks>
		/// <value>Width of Columns.</value>
		public double ColumnWidth
		{
			get { return columnWidth; }
			set
			{
				if (columnWidth != value)
				{
					columnWidth = value;
					NotifyPropertyChanged("ColumnWidth");
				}
			}
		}
		#endregion ColumnWidth

		#region ColumnBrush
		Brush columnBrush;
		/// <summary>
		/// Gets or sets the <see cref="ColumnBrush"/> property.
		/// </summary>
		/// <remarks>
		/// If the <see cref="ColumnBrush"/> isn't set the <see cref="Pen"/> Brush is used instead.
		/// </remarks>
		/// <value>Brush the column is drawn with.</value>
		public Brush ColumnBrush
		{
			get { return columnBrush != null ? columnBrush : Pen.Brush; }
			set
			{
				if (columnBrush != value)
				{
					if (columnBrush != null && !columnBrush.IsFrozen)
						columnBrush.Changed -= ColumnBrushChanged;
					columnBrush = value;
					if (columnBrush != null && !columnBrush.IsFrozen)
						columnBrush.Changed += ColumnBrushChanged;
					NotifyPropertyChanged("ColumnBrush");
				}
			}
		}

		/// <summary>
		/// ColumnBrush changed.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		void ColumnBrushChanged(object sender, EventArgs e)
		{
			NotifyPropertyChanged("ColumnBrush");
		}
		#endregion ColumnBrush

		#region ICloneable Override
		/// <summary>
		/// Creates a new object that is a copy of the current instance.
		/// </summary>
		/// <returns>
		/// A new object that is a copy of this instance.
		/// </returns>
		/// <remarks>This method is designed to provide the deep cloning facility if desired.</remarks>
		protected override object CloneInternal()
		{
			ColumnChartItemDataView clone = base.CloneInternal() as ColumnChartItemDataView;
			// ColumnBrush.
			if (columnBrush != null)
			{
				clone.columnBrush = columnBrush.Clone();
				clone.columnBrush.Changed += clone.ColumnBrushChanged;
			}
			return clone;
		}
		#endregion ICloneable Override

		#region IDataErrorInfo Overrides
		/// <inheritdoc />
		protected override string ObjectErrorInfo
		{
			get
			{
				StringBuilder sb = new StringBuilder(base.ObjectErrorInfo);
				string s = base.GetDataErrorInfo("ColumnWidth");
				if (!string.IsNullOrEmpty(s))
				{
					if (sb.Length > 0)
						sb.Append(Environment.NewLine);
					sb.Append(s);
				}
				if (sb.Length > 0)
					return sb.ToString();
				return null;
			}
		}

		/// <inheritdoc />
		protected override string GetDataErrorInfo(string columnName)
		{
			switch (columnName)
			{
				case "ColumnWidth":
					return ColumnWidth <= 0 ? "ColumnWidth must be positive" : null;
			}
			return base.GetDataErrorInfo(columnName);
		}
		#endregion IDataErrorInfo Overrides
	}
}
